package com.wk.playersdk;


import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.text.TextUtils;

import com.wk.playersdk.bean.MuteEnum;
import com.wk.playersdk.bean.TimeInfoBean;
import com.wk.playersdk.util.WkException;
import com.wk.playersdk.util.WkLog;
import com.wk.playersdk.util.WkThreadPoolTools;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

public class WkPlayer {

    static {
        System.loadLibrary("wkPlayer");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avdevice-57");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avformat-57");
        System.loadLibrary("avutil-55");
        System.loadLibrary("postproc-54");
        System.loadLibrary("swresample-2");
        System.loadLibrary("swscale-4");

    }

    private PlayerStateListener playerStateListener ;
    private WkThreadPoolTools  wkThreadPoolTools ;
    private static TimeInfoBean timeInfoBean;
    //private boolean isCirclePlay = false ;
    /**是否要播放下一首*/
    private static boolean playNext = true;
    /**当前播放进度*/
    private int currentProgress = -1 ;
    private static int volumePercent = 50;
    private static float speed = 1.0f;
    private static float pitch = 1.0f;
    private static boolean initmediacodec = false;
    private static MuteEnum muteEnum = MuteEnum.MUTE_CENTER;
    private MediaFormat encoderFormat = null;
    private MediaCodec encoder = null;
    private FileOutputStream outputStream = null;
    private MediaCodec.BufferInfo info = null;
    private int perpcmsize = 0;
    private byte[] outByteBuffer = null;
    /**aac 添加头信息时需要的采样率下标*/
    private int aacsamplerate = 4;
    private double recordTime = 0;
    /**音频采样率*/
    private int audioSamplerate = 0;
    private boolean isCircle = true ;




    public native void n_preparePlayer(String source);
    public native void n_startPlayer();
    private native void n_pause();
    private native void n_resume();
    private native void n_stop();
    private native void n_seek(int secds);
    private native int n_duration();
    private native void n_volume(int percent);
    private native void n_mute(int mute);
    private native void n_pitch(float pitch);
    private native void n_speed(float speed);
    private native int n_samplerate();
    private native void n_startstoprecord(boolean start);
    private native void n_setCirclePlay(boolean isCircle);


    /**
     * 以ByN 结尾的函数都是被c++调用的。
     * 准备结束
     * */
    public void onPreparedByN(){
        playerStateListener.onPrepared();
    }

    public void onLoadByN(boolean isLoad){
        playerStateListener.onLoad(isLoad);

    }

    private void onErrorByN(int code  ,String msg){
        playerStateListener.onError(code , msg);
        stop();

    }

    public void onCallNextByN()
    {
        if(playNext ||  isCircle)
        {
            playNext = false;
            preparePlayer();
        }
    }


    public void onComplateByN(){
        playerStateListener.onComplate();

        WkLog.e("播放完成 ... isCircle="+ isCircle);
        if(isCircle){
            stop();
        }
    }

    public WkPlayer(PlayerStateListener listener){
        playerStateListener = listener ;
        wkThreadPoolTools = new WkThreadPoolTools();

    }

    public void onCallTimeInfoByN(int currentTime, int totalTime) {
        if(timeInfoBean == null)
        {
            timeInfoBean = new TimeInfoBean();
        }
        timeInfoBean.setCurrentTime(currentTime);
        timeInfoBean.setTotalTime(totalTime);
        playerStateListener.onTimeInfo(timeInfoBean);
    }


    public void onCallValumeDBByN(int db) {
        playerStateListener.onDbValue(db);
    }

    private void encodecPcmToAAcByN(int size, byte[] buffer)
    {
        if(buffer != null && encoder != null)
        {
            recordTime += size * 1.0 / (audioSamplerate * 2 * (16 / 8));
            playerStateListener.onRecordTime((int) recordTime);

            int inputBufferindex = encoder.dequeueInputBuffer(0);
            if(inputBufferindex >= 0)
            {
                WkLog.d("1 inputBufferindex= "+inputBufferindex);
                WkLog.d("2 buffer length= "+buffer.length);
                ByteBuffer byteBuffer = encoder.getInputBuffers()[inputBufferindex];

                WkLog.d("3 capacity= "+byteBuffer.capacity());

                boolean hasArray = byteBuffer.hasArray();
                WkLog.d("4 hasArray= "+hasArray);
                //java.lang.UnsupportedOperationException   ,  DirectByteBuffer.protectedArray
                if(byteBuffer.array() !=null){
                    WkLog.d("2 buffer= "+byteBuffer.array().length+"  "+byteBuffer.capacity());
                }
                // 清空缓冲区
                byteBuffer.clear();
                byteBuffer.put(buffer);
                encoder.queueInputBuffer(inputBufferindex, 0, size, 0, 0);
            }

            int index = encoder.dequeueOutputBuffer(info, 0);
            while(index >= 0)
            {
                try {
                    perpcmsize = info.size + 7;
                    outByteBuffer = new byte[perpcmsize];

                    ByteBuffer byteBuffer = encoder.getOutputBuffers()[index];
                    byteBuffer.position(info.offset);
                    byteBuffer.limit(info.offset + info.size);

                    addADtsHeader(outByteBuffer, perpcmsize, aacsamplerate);

                    byteBuffer.get(outByteBuffer, 7, info.size);
                    byteBuffer.position(info.offset);
                    outputStream.write(outByteBuffer, 0, perpcmsize);

                    encoder.releaseOutputBuffer(index, false);
                    index = encoder.dequeueOutputBuffer(info, 0);
                    outByteBuffer = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void addADtsHeader(byte[] packet, int packetLen, int samplerate)
    {
        // AAC LC
        int profile = 2;
        // 采样率下标
        int freqIdx = samplerate;
        // 2 声道
        int chanCfg = 2;

        // 0xFFF(12bit) 这里只取了8位，所以还差4位放到下一个里面
        packet[0] = (byte) 0xFF;
        // 第一个t位放F
        packet[1] = (byte) 0xF9;
        packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
        packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
        packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
        packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
        packet[6] = (byte) 0xFC;
    }


    /**
     * 初始化解码器
     * @param samperate 采样率
     * @param outfile 录音文件存储路径
     */
    private void initMediacodec(int samperate, File outfile)
    {
        try {
            aacsamplerate = getADTSsamplerate(samperate);
            encoderFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, samperate, 2);
            // 设置比特率
            encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000);
//            encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, 44100);
            encoderFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            //设置编码器最大的缓冲区 大小  4096
            encoderFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 4096  );
            encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
            info = new MediaCodec.BufferInfo();
            if(encoder == null)
            {
                return;
            }
            recordTime = 0;
            encoder.configure(encoderFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            outputStream = new FileOutputStream(outfile);
            encoder.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据采样率获得采样率下标。
     * 这个对应关系是对应的
     */
    private int getADTSsamplerate(int samplerate)
    {
        int rate = 4;
        switch (samplerate)
        {
            case 96000:
                rate = 0;
                break;
            case 88200:
                rate = 1;
                break;
            case 64000:
                rate = 2;
                break;
            case 48000:
                rate = 3;
                break;
            case 44100:
                rate = 4;
                break;
            case 32000:
                rate = 5;
                break;
            case 24000:
                rate = 6;
                break;
            case 22050:
                rate = 7;
                break;
            case 16000:
                rate = 8;
                break;
            case 12000:
                rate = 9;
                break;
            case 11025:
                rate = 10;
                break;
            case 8000:
                rate = 11;
                break;
            case 7350:
                rate = 12;
                break;
            default:
                break;
        }
        return rate;
    }


    /***
     * 播放数据源
     */
    private String source ;

    public void setSource(String source) {
        this.source = source;
    }

    /**
     * 准备播放
     */
    public void preparePlayer(){
        if(TextUtils.isEmpty(source)){
            WkLog.e("播放数据源为空");
            return;
        }

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                n_preparePlayer(source);
            }
        };
        wkThreadPoolTools.addTask(runnable);
    }


    public void pause(){
        n_pause();
        playerStateListener.onPause(true);
    }

    public void resume(){
        n_resume();
        playerStateListener.onPause(false);
    }

    public void playNext(String source){
        this.source = source ;
        playNext = true ;
        stop();
    }

    /**
     * 启动播放器
     */
    public void start(){
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                setMute(muteEnum);
                n_startPlayer();
                setVolume(volumePercent);
            }
        } ;
        wkThreadPoolTools.addTask(runnable);
    }

    /**
     * 停止播放器
     */
    public void stop()
    {
        timeInfoBean = null;
        currentProgress = -1 ;
        stopRecord();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                n_stop();
            }
        };
        wkThreadPoolTools.addTask(runnable);
    }


    /**
     * 释放解码器
     */
    private void releaseMedicacodec()
    {
        if(encoder == null)
        {
            return;
        }
        try {
            recordTime = 0;
            outputStream.close();
            outputStream = null;
            encoder.stop();
            encoder.release();
            encoder = null;
            encoderFormat = null;
            info = null;
            initmediacodec = false;
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if(outputStream != null)
            {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                outputStream = null;
            }
        }
    }


    /**
     * 修改opensl 的播放音量
     */
    public void setVolume(int percent)
    {
        if(percent >=0 && percent <= 100)
        {
            volumePercent = percent;
            n_volume(percent);
        }
    }



    /**获得当前播放进度*/
    public int getDuration(){
        currentProgress =n_duration() ;
        return  currentProgress ;
    }

    /**改变播放进度*/
    public void seek(int second){
        n_seek(second);
    }

    public int getVolumePercent()
    {
        return volumePercent;
    }

    /**
     * 设置混音器
     */
    public void setMute(MuteEnum mute)
    {
        muteEnum = mute;
        n_mute(mute.getValue());
    }

    public void setPitch(float p)
    {
        pitch = p;
        n_pitch(pitch);
    }

    /**
     * 变速功能  1.0 是正常速度 ， 大于1.0是加速播放
     */
    public void setSpeed(float s)
    {
        speed = s;
        n_speed(speed);
    }

    public void startRecord(File localFile){

        if(!initmediacodec){
            audioSamplerate = n_samplerate() ;
            if(audioSamplerate >0){
                initmediacodec = true ;
                initMediacodec(audioSamplerate , localFile);
                n_startstoprecord(true);
            }
        }
    }


    public void pauseRecord(){
        n_startstoprecord(false);
    }

    public void reSumeRecord(){
        n_startstoprecord(true);

    }


    public void stopRecord()
    {
        if(initmediacodec)
        {
            n_startstoprecord(false);
            releaseMedicacodec();
        }
    }



    public void setCirclePlay(boolean circlePlay)  {
        isCircle = circlePlay ;
//        n_setCirclePlay(circlePlay);
      /*  if(source==null || source.contains("http") || source.contains("https")){
            throw new WkException(1001 ,"循环播放 只支持本地音频") ;
        }else{
            n_setCirclePlay(circlePlay);
        }*/

    }

}
